/**
 * WebRTC 视频播放器类
 * 用于通过 WebRTC 协议播放视频流
 */
class WebRtcPlayer {
  // 静态服务器地址，可通过 setServer 方法修改
  static server = '127.0.0.1:8083';

  // 实例属性
  private webrtc: RTCPeerConnection | null = null;
  private video: HTMLVideoElement | null = null;
  private server: string;
  private codecLink: string = '';
  private rsdpLink: string = '';
  private stream: MediaStream = new MediaStream();
  private uuid: string;
  private options: {
    onStatusChange?: (status: string) => void;
  };

  /**
   * 构造函数
   * @param id 视频元素的 ID
   * @param uuid 视频流的唯一标识符
   * @param options 配置选项
   */
  constructor(
    id: string,
    uuid: string,
    options: { onStatusChange?: (status: string) => void } = {}
  ) {
    this.server = WebRtcPlayer.server;
    this.video = document.getElementById(id) as HTMLVideoElement;
    this.uuid = uuid;
    this.options = { ...options };

    if (!this.video) {
      console.error(`Video element with id ${id} not found`);
      return;
    }

    this.createLinks();
    this.webrtc = new RTCPeerConnection({
      iceServers: [
        {
          urls: ['stun:stun.l.google.com:19302'],
        },
      ],
    });

    this.play();
  }

  /**
   * 创建连接链接
   */
  private createLinks(): void {
    this.codecLink = '//' + this.server + '/stream/codec/' + this.uuid;
    this.rsdpLink = '//' + this.server + '/stream/receiver/' + this.uuid;
  }

  /**
   * 开始播放视频
   */
  play(): void {
    if (!this.webrtc) return;

    this.webrtc.onnegotiationneeded = this.handleNegotiationNeeded.bind(this);
    this.webrtc.ontrack = this.onTrack.bind(this);

    fetch(this.codecLink)
      .then(response => {
        response.json().then(data => {
          if (!this.webrtc) return;

          data.forEach((item: { Type: string }) => {
            this.webrtc?.addTransceiver(item.Type, {
              direction: 'sendrecv',
            });
          });
        });
      })
      .catch(error => {
        console.error('Error fetching codec:', error);
        this.options.onStatusChange?.('error');
      });
  }

  /**
   * 处理协商需求
   */
  private async handleNegotiationNeeded(): Promise<void> {
    if (!this.webrtc) return;

    try {
      const offer = await this.webrtc.createOffer();
      await this.webrtc.setLocalDescription(offer);

      const formData = new FormData();
      formData.append('suuid', this.uuid);
      formData.append('data', btoa(this.webrtc.localDescription?.sdp || ''));

      fetch(this.rsdpLink, {
        method: 'POST',
        body: formData,
      })
        .then(response => {
          response.text().then(data => {
            if (!this.webrtc) return;

            this.webrtc.setRemoteDescription(
              new RTCSessionDescription({
                type: 'answer',
                sdp: atob(data),
              })
            );

            this.options.onStatusChange?.('connected');
          });
        })
        .catch(err => {
          console.error('Error setting remote description:', err);
          this.options.onStatusChange?.('error');
        });
    } catch (error) {
      console.error('Error during negotiation:', error);
      this.options.onStatusChange?.('error');
    }
  }

  /**
   * 处理轨道事件
   * @param event 轨道事件
   */
  private onTrack(event: RTCTrackEvent): void {
    if (!this.video) return;

    this.stream.addTrack(event.track);
    this.video.srcObject = this.stream;
    this.video
      .play()
      .then(() => {
        this.options.onStatusChange?.('playing');
      })
      .catch(error => {
        console.error('Error playing video:', error);
        this.options.onStatusChange?.('error');
      });
  }

  /**
   * 加载新的视频流
   * @param uuid 视频流的唯一标识符
   */
  load(uuid: string): void {
    this.destroy();
    this.uuid = uuid;
    this.createLinks();

    this.webrtc = new RTCPeerConnection({
      iceServers: [
        {
          urls: ['stun:stun.l.google.com:19302'],
        },
      ],
    });

    this.play();
  }

  /**
   * 销毁播放器实例
   */
  destroy(): void {
    if (this.webrtc) {
      this.webrtc.close();
      this.webrtc = null;
    }

    if (this.video) {
      this.video.srcObject = null;
    }

    this.stream = new MediaStream();
  }

  /**
   * 获取当前视频帧的图像 URL
   * @returns 图像的 Data URL
   */
  getImageUrl(): string | null {
    if (!this.video) return null;

    const canvas = document.createElement('canvas');
    canvas.width = this.video.videoWidth;
    canvas.height = this.video.videoHeight;

    const context = canvas.getContext('2d');
    if (!context) return null;

    context.drawImage(this.video, 0, 0, canvas.width, canvas.height);
    const dataURL = canvas.toDataURL();

    canvas.remove();
    return dataURL;
  }

  /**
   * 设置服务器地址
   * @param serv 服务器地址
   */
  static setServer(serv: string): void {
    WebRtcPlayer.server = serv;
  }
}

export default WebRtcPlayer;
